package com.fei.test;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileFilter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.io.MemoryUsageSetting;
import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import http.HttpClientUtil;
import util.JsonUtils;
import util.XMLDoc;

public class Upload {
    private static Map<String, Map<String, Object>> uploadFile(File file) {
        String url = "http://api.wdku.net/ocr/Upload.php";
        String partName = "file";
        String filePath = file.getAbsolutePath();
        Map<String, String> params = null;
        String contentType = "text/html; charset=UTF-8";
        String result = HttpClientUtil.uploadFile(url, partName, filePath,
                params, contentType);
        Map<String, Map<String, Object>> data = JsonUtils.readJson2Map(result);

        return data;
    }

    private static String submitOrc(String type,
            Map<String, Map<String, Object>> data) throws Exception {
        String fileId = "";
        String submitUrl = "http://ocr.wdku.net/submitOcr?type=1";
        String id = data.get("data").get("id").toString();
        Map<String, String> params = new HashMap<String, String>();
        params.put("obj_type", type);
        params.put("ids", id);
        params.put("ts", data.get("data").get("time").toString());
        params.put("pass", "");
        Map<String, String> headers = new HashMap<String, String>();

        String result = HttpClientUtil.executePost(submitUrl, headers, params);
        Map<String, String> d = JsonUtils.readJson2Map(result, String.class);
        System.out.println("提交转换返回：" + result);
        System.out.println("提交转换返回：" + d.get("desc"));

        for (;;) {
            if (!d.get("errno").equals("0")) {
                HostProxy hostProxy = getHostProxy();
                String hostname = hostProxy.getHostname();
                int port = hostProxy.getPort();
                System.out.println("提交转换失败,尝试使用新HOST:" + hostname + ":" + port);

                // 切换HOST
                HttpClientUtil.reloadProxyConfig(hostname, port, "", "");
                result = HttpClientUtil.executePost(submitUrl, headers, params);
                d = JsonUtils.readJson2Map(result, String.class);
            }
            else {
                fileId = d.get("id");
                System.out.println("提交转换成功：" + d.get("desc"));
                break;
            }
        }

        return fileId;

    }

    private static Map<String, String> waitFor(String id) throws Exception {
        String waitResult = "http://ocr.wdku.net/waitResult";

        Map<String, String> params = new HashMap<String, String>();
        params.put("id", id);

        Map<String, String> d = null;
        boolean flag = true;
        while (flag) {
            try {
                String result = HttpClientUtil.executeGet(waitResult, params);
                d = JsonUtils.readJson2Map(result, String.class);

                System.out.println("等待生成结果：" + result);
                System.out.println("等待生成结果：" + d.get("desc"));
                flag = false;
            }
            catch (Exception e) {
                System.out.println("等待生成结果出错：" + e.getMessage());
                HostProxy hostProxy = getHostProxy();
                String hostname = hostProxy.getHostname();
                int port = hostProxy.getPort();

                System.out.println("尝试切换IP后继续等待：" + hostname + ":" + port);
                // 切换HOST
                HttpClientUtil.reloadProxyConfig(hostname, port, "", "");
            }
        }

        return d;
    }

    private static void getFile(String fileName, String id, String outPutPath,
            String type) throws Exception {

        for (;;) {
            Map<String, String> d = waitFor(id);
            if (d.get("errno").equals("0")) {
                if (!"Success".equals(d.get("desc"))
                        && !"等待转换".equals(d.get("desc"))) {
                    System.out.println("转换有问题，抛出异常重新转换当前文件：" + d.get("desc"));
                    throw new Exception(d.get("desc"));
                }
                else if ("Success".equals(d.get("desc"))) {
                    break;
                }
            }

            try {
                Thread.sleep(5000);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("继续等待返回结果：" + d.get("desc"));
        }

        System.out.println("开始下载==========================");
        String downResult = "http://ocr.wdku.net/downResult";

        Map<String, String> params = new HashMap<String, String>();
        params.put("id", id);

        String name = "";
        if (fileName.contains(".")) {
            name = fileName.substring(0, fileName.indexOf("."));
        }
        String filePath = outPutPath + name + "." + type;

        boolean flag = true;
        while (flag) {
            try {
                HttpClientUtil.downLoadFile(downResult, filePath, params);
                flag = false;
            }
            catch (Exception e) {
                System.out
                        .println("下载出错：" + e.getMessage() + ",准备删除失败文件后重新下载。");
                File tmpFile = new File(filePath);
                if (tmpFile.exists()) {
                    tmpFile.delete();
                }
                HostProxy hostProxy = getHostProxy();
                String hostname = hostProxy.getHostname();
                int port = hostProxy.getPort();

                System.out.println("尝试切换IP重新下载：" + hostname + ":" + port);
                // 切换HOST
                HttpClientUtil.reloadProxyConfig(hostname, port, "", "");
            }
        }

    }

    private static Comparator<File> sortFile() {
        Comparator<File> c = new Comparator<File>() {
            public int compare(File o1, File o2) {
                String n1 = o1.getName().substring(
                        o1.getName().indexOf("_") + 1,
                        o1.getName().indexOf("."));
                String n2 = o2.getName().substring(
                        o2.getName().indexOf("_") + 1,
                        o2.getName().indexOf("."));
                int i1 = Integer.valueOf(n1);
                int i2 = Integer.valueOf(n2);

                if (i1 > i2) {
                    return 1;
                }
                else {
                    return -1;
                }
            }
        };

        return c;
    }

    /**
     * 获取文件
     * 
     * @param path
     * @return
     */
    private static List<File> getFiles(String path) {
        File dir = new File(path);

        List<File> files = new ArrayList<>();

        if (!dir.exists()) {
            return files;
        }

        files.addAll(Arrays.asList(dir.listFiles(new FileFilter() {
            
            @Override
            public boolean accept(File file) {
                if(file.isDirectory()){
                    return false;
                }
                return true;
            }
        })));
        Collections.sort(files, sortFile());

        return files;
    }

    private static String getXmlData(String url) {
        Map<String, String> headers = new HashMap<>();

        headers.put("User-Agent",
                " Mozilla/5.0 (Windows NT 6.1; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0");
        String result = HttpClientUtil.executeGet(url, headers, null);

        result = result.substring(result.indexOf("<table") - 1,
                result.lastIndexOf("table") + 6);

        return result;
    }

    /**
     * 获取快代理服务器地址
     * 
     * @param resultList
     * @param nodeList
     * @throws Exception
     */
    private static void getKuaiDaiLi(List<HostProxy> resultList)
            throws Exception {

        String url = "http://www.kuaidaili.com/free/inha/";

        String result = getXmlData(url);

        XMLDoc xml = new XMLDoc();
        xml.loadFromXMLString(result);
        NodeList nodeList = xml.getRootElement().getChildNodes();

        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);

            if (!(node instanceof Element)) {
                continue;
            }

            Element element = (Element) node;

            NodeList tdList = element.getChildNodes();

            int index = 0;
            Node ip = null;
            Node port = null;

            for (int j = 0; j < tdList.getLength(); j++) {
                Node td = tdList.item(j);

                if (!(td instanceof Element)) {
                    continue;
                }

                switch (index) {
                    case 0:
                        // ip
                        ip = td;
                        break;
                    case 1:
                        // 端口
                        port = td;
                        break;
                }

                index++;
            }

            HostProxy h = new HostProxy(ip.getTextContent(),
                    Integer.valueOf(port.getTextContent()));

            resultList.add(h);
        }
    }

    /**
     * 获取嘻嘻代理服务器地址
     * 
     * @param resultList
     * @param nodeList
     * @throws Exception
     */
    private static void getXiCiDaili(List<HostProxy> resultList)
            throws Exception {
        String url = "http://www.xicidaili.com/nn/";

        String result = getXmlData(url);

        XMLDoc xml = new XMLDoc();
        xml.loadFromXMLString(result);
        NodeList nodeList = xml.getRootElement().getChildNodes();

        int continueRow = 0;
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);

            if (!(node instanceof Element)) {
                continue;
            }

            if (continueRow == 0) {
                continueRow = 1;
                continue;
            }

            Element element = (Element) node;

            NodeList tdList = element.getChildNodes();

            int index = 0;
            Node ip = null;
            Node port = null;
            Node speed = null;
            Node live = null;
            for (int j = 0; j < tdList.getLength(); j++) {
                Node td = tdList.item(j);

                if (!(td instanceof Element)) {
                    continue;
                }

                switch (index) {
                    case 1:
                        // ip
                        ip = td;
                        break;
                    case 2:
                        // 端口
                        port = td;
                        break;
                    case 6:
                        // 链接速度
                        speed = td;
                        break;
                    case 8:
                        // 存活天数
                        live = td;
                        break;
                }

                index++;
            }

            int speedFlag = 0;
            Element speedElement = (Element) speed;
            NodeList speedList = XMLDoc.getElementsByTagName(speedElement,
                    "div");
            for (int s = 0; s < speedList.getLength(); s++) {
                Node sNode = speedList.item(s);
                if (!(sNode instanceof Element)) {
                    continue;
                }

                Element sElement = (Element) sNode;
                String className = sElement.getAttribute("class");
                if (className.contains("fast")) {
                    speedFlag = 1;
                }
                else if (className.contains("medium")) {
                    speedFlag = 2;
                }
                else if (className.contains("slow")) {
                    speedFlag = 3;
                }

            }

            int hours = getHours(live.getTextContent());

            HostProxy h = new HostProxy(ip.getTextContent(),
                    Integer.valueOf(port.getTextContent()));

            if (speedFlag > 0) {
                h.setSpeed(speedFlag);
            }
            else {
                h.setSpeed(Integer.MAX_VALUE);
            }

            if (hours > 0) {
                h.setLive(hours);
            }
            else {
                h.setLive(-1);
            }

            resultList.add(h);
        }

        // Collections.sort(resultList, compareBySpeedAndLiveTime());
    }

    /**
     * 获取代理服务器列表
     * 
     * @throws Exception
     */
    private static List<HostProxy> getProxyList() throws Exception {
        List<HostProxy> resultList = new ArrayList<>();
        // 先添加收集数据
        Map<String, HostProxy> cacheData = getRecordHttp();
        for (Entry<String, HostProxy> entry : cacheData.entrySet()) {
            String ip = entry.getKey();
            HostProxy p = entry.getValue();

            if (p.getSuccessTime() == 0) {
                continue;
            }

            resultList.add(p);
        }

        Collections.sort(resultList, compareBySuccess());

        // 获取代理地址
        getXiCiDaili(resultList);

        // 获取快代理地址
        // getKuaiDaiLi(resultList, nodeList);

        return resultList;
    }

    /**
     * 获取时间
     * 
     * @param textContent
     * @return
     */
    private static int getHours(String textContent) {
        char[] strs = textContent.toCharArray();
        int result = 0;
        for (int i = 0; i < strs.length; i++) {
            char c = strs[i];

            if (c == '天') {
                char[] tmp = Arrays.copyOfRange(strs, 0, i);
                String data = String.valueOf(tmp);
                result = Integer.valueOf(data) * 24;
            }
            else if (c == '小') {
                char[] tmp = Arrays.copyOfRange(strs, 0, i);
                String data = String.valueOf(tmp);
                result = Integer.valueOf(data);
            }
            else if (c == '分') {
                char[] tmp = Arrays.copyOfRange(strs, 0, i);
                String data = String.valueOf(tmp);
                result = Integer.valueOf(data) / 60;
            }
        }
        return result;
    }

    /**
     * 根据链接速度排序
     * 
     * @return
     */
    private static Comparator<HostProxy> compareBySpeedAndLiveTime() {
        Comparator<HostProxy> c = new Comparator<HostProxy>() {

            @Override
            public int compare(HostProxy o1, HostProxy o2) {
                if (o1.getLive() < o2.getLive()) {
                    return 1;
                }
                else if (o1.getLive() == o2.getLive()) {
                    return 0;
                }
                else {

                    return -1;
                }
            }
        };
        return c;
    }

    private static List<HostProxy> statis_host_list = new ArrayList<HostProxy>();

    private static List<HostProxy> used_host_list = new ArrayList<HostProxy>();

    private synchronized static List<HostProxy> putOrGetUsedHost(
            HostProxy hostProxy) {
        if (hostProxy == null) {
            return used_host_list;
        }
        else {
            used_host_list.add(hostProxy);
            return null;
        }
    }

    private static HostProxy currentProxy = null;

    private static HostProxy getHostProxy() throws Exception {
        if (currentProxy != null) {
            putOrGetUsedHost(currentProxy);
        }

        if (statis_host_list.isEmpty()) {
            statis_host_list.addAll(getProxyList());
        }

        if (statis_host_list.isEmpty()) {
            System.out.println("无法获取新的HOST文件");
            System.exit(0);
        }

        HostProxy p = statis_host_list.get(0);

        statis_host_list.remove(0);
        currentProxy = p;
        return p;
    }

    /**
     * 转换文件
     * 
     * @param path
     * @param outPutPath
     * @param type
     * @throws Exception
     */
    private static void tranFile(String path, String outPutPath, String type)
            throws Exception {
        boolean flag = true;
        while (flag) {
            // 获取文件
            List<File> files = getFiles(path);
            try {
                for (File file : files) {

                    // 上传文件
                    Map<String, Map<String, Object>> data = uploadFile(file);
                    String id = submitOrc(type, data);
                    getFile(file.getName(), id, outPutPath, type);

                    if (currentProxy != null) {
                        currentProxy.setSuccessTime(
                                currentProxy.getSuccessTime() + 1);
                    }
                    System.out.println("成功转换：" + file.getName());
                    file.delete();
                }

                if (files.isEmpty()) {
                    System.out.println("全部转换完成！！！！！！！！！！！！！！！！！！！！！！！！！！！！");
                    flag = false;
                }

            }
            catch (Exception e) {
                HostProxy hostProxy = getHostProxy();
                String hostname = hostProxy.getHostname();
                int port = hostProxy.getPort();

                System.out.println("发生错误：" + e.getMessage());
                System.out.println("尝试切换IP重新请求：" + hostname + ":" + port);
                // 切换HOST
                HttpClientUtil.reloadProxyConfig(hostname, port, "", "");
            }
        }
    }

    private static void mergePDF(String outPutPath) throws Exception {
        // 合并PDF
        List<File> pdfFiles = getFiles(outPutPath);
        PDFMergerUtility mergePdf = new PDFMergerUtility();

        String finalName = "";
        for (File f : pdfFiles) {
            mergePdf.addSource(f);

            if (StringUtils.isEmpty(finalName)) {
                finalName = f.getName().substring(0, f.getName().indexOf("_"))
                        + ".pdf";
            }
        }

        if (!StringUtils.isEmpty(finalName)) {
            mergePdf.setDestinationFileName(outPutPath + finalName);
            mergePdf.mergeDocuments(null);
        }
    }

    /**
     * PDF 转图片
     * 
     * @param pdfFilePath
     * @param imgPath
     */
    private static void toImage(String pdfFilePath, String imgPath) {
        PDDocument doc = null;
        try {
            File pdfFile = new File(pdfFilePath);
            if (pdfFile.getName().contains("checked")) {
                // 图片已经转换完成
                return;
            }
            doc = PDDocument.load(pdfFile);
            PDFRenderer renderer = new PDFRenderer(doc);
            int pageCount = doc.getNumberOfPages();

            long timeStart = System.currentTimeMillis();
            System.out.println("准备开始转换图片，共：" + (pageCount + 1) + "页.");

            int threadPage = 0;
            int maxThread = 10;

            if (pageCount % maxThread == 0) {
                threadPage = pageCount / maxThread;
            }
            else {
                threadPage = (pageCount / maxThread) + 1;
            }

            List<TransImageTask> taskList = new ArrayList<>();
            for (int index = 0; index < maxThread; index++) {

                int nextPage = (index + 1) * threadPage;
                if (nextPage >= pageCount) {
                    nextPage = pageCount;
                }

                TransImageTask task = new TransImageTask(index * threadPage,
                        nextPage, pdfFile.getName(), renderer, imgPath);
                task.start();

                taskList.add(task);

            }

            for (TransImageTask task : taskList) {
                try {
                    task.join();
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            // 完成图片转换后重命名PDF
            String destPath = pdfFile.getAbsolutePath().substring(0,
                    pdfFile.getAbsolutePath().lastIndexOf(".")) + "checked"
                    + ".pdf";
            pdfFile.renameTo(new File(destPath));

            long endTime = System.currentTimeMillis();
            System.out.println("完成图片转换，重新命名文件：" + destPath + ",总共耗时："
                    + (endTime - timeStart) / 100 + "s");
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            if (doc != null) {
                try {
                    doc.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static Map<String, HostProxy> getRecordHttp() {
        BufferedReader reader = null;
        try {
            File file = new File("ip.data");
            if (!file.exists()) {
                return null;
            }

            reader = new BufferedReader(new FileReader(file));
            Map<String, HostProxy> data = new HashMap<>();
            String line = null;
            while ((line = reader.readLine()) != null) {
                if (StringUtils.isEmpty(line)) {
                    continue;
                }

                String[] strs = line.split(":");
                String ip = strs[0];
                int port = Integer.valueOf(strs[1]);
                int success = Integer.valueOf(strs[2]);
                HostProxy p = new HostProxy(ip, port);
                p.setSuccessTime(success);

                data.put(ip, p);
            }

            return data;
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        finally {
            if (reader != null) {
                try {
                    reader.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 比较成功次数
     * 
     * @return
     */
    private static Comparator<HostProxy> compareBySuccess() {
        Comparator<HostProxy> c = new Comparator<HostProxy>() {

            @Override
            public int compare(HostProxy o1, HostProxy o2) {
                if (o1.getSuccessTime() > o2.getSuccessTime()) {
                    return -1;
                }
                else if (o1.getSuccessTime() == o2.getSuccessTime()) {
                    return 0;
                }
                else {
                    return 1;
                }
            }

        };

        return c;
    }

    private static boolean collectDataFlag = true;

    /**
     * 异步收集成功率较高的IP
     */
    private static void collectData() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                while (collectDataFlag) {
                    List<HostProxy> tmpList = putOrGetUsedHost(null);
                    Collections.sort(tmpList, compareBySuccess());

                    saveOrUpdateData(tmpList);

                    try {
                        Thread.sleep(5000 * 60);
                    }
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

            /**
             * 保存或者更新数据
             * 
             * @param tmpList
             * @throws IOException
             */
            private void saveOrUpdateData(List<HostProxy> tmpList) {
                if (tmpList == null || tmpList.size() == 0)
                    return;

                System.out.println("开始收集数据======================");
                Map<String, HostProxy> data = getRecordHttp();
                for (HostProxy h : tmpList) {
                    String ip = h.getHostname();
                    int successTimes = h.getSuccessTime();
                    if (successTimes == 0) {
                        continue;
                    }

                    if (data == null || !data.containsKey(ip)) {
                        if (data == null) {
                            data = new HashMap<>();
                        }
                        data.put(ip, h);
                    }
                    else {
                        HostProxy tmp = data.get(ip);
                        if (tmp.getSuccessTime() < successTimes) {
                            tmp.setSuccessTime(successTimes);
                        }
                        else {
                            System.out.println(ip + ",记录次数大于当前次数，不做更新。记录次数："
                                    + tmp.getSuccessTime() + ",当前次数："
                                    + successTimes);
                        }

                        data.put(ip, tmp);

                    }
                }

                this.addData(data);

                System.out
                        .println("收集数据完成====================================");
            }

            private void addData(Map<String, HostProxy> data) {
                BufferedWriter writer = null;
                try {
                    File file = new File("ip.data");
                    file.delete();
                    if (!file.exists()) {
                        file.createNewFile();
                    }

                    writer = new BufferedWriter(new FileWriter(file));

                    for (Entry<String, HostProxy> e : data.entrySet()) {
                        HostProxy h = e.getValue();

                        String line = h.getHostname() + ":" + h.getPort() + ":"
                                + h.getSuccessTime() + "\n";

                        writer.write(line);
                    }

                    writer.flush();
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
                finally {
                    if (writer != null) {
                        try {
                            writer.close();
                        }
                        catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }

            }

        }).start();
    }

    public static void main(String[] args) throws Exception {/*
        // String pdfFilePath = "/home/wangfei/study/Redis入门指南（第2版）.pdf";
        String pdfFilePath = "E:\\技术资料\\高级需求分析师20141114（改）.pdf";
        String imgPath = "E:\\pdf\\img\\";
        String outPutPath = "E:\\pdf\\doc\\";
        String type = "pdf";

        // 异步收集数据
        collectData();

        System.out.println("#################开始转换图片########################");
//        toImage(pdfFilePath, imgPath);
        System.out.println("#################完成转换图片########################");

        System.out.println("#################开始解析图片########################");
        tranFile(imgPath, outPutPath, type);
        System.out.println("#################完成解析图片########################");

        System.out.println("#################开始合并PDF########################");
        mergePDF(outPutPath);
        System.out.println("#################完成合并PDF########################");

        System.out.println("结束运行");

        // 停止收集数据，结束任务
        collectDataFlag = false;
    */
//        String url = "http://www.javaxxz.com/?fromuser=wangfei_2010";
        String url = "http://119.254.109.162/";
        
        

        int index = 0;
        boolean flag = true;
        while(flag){
        try{
            HostProxy hostProxy = getHostProxy();
            String hostname = hostProxy.getHostname();
            int port = hostProxy.getPort();
        // 切换HOST
        HttpClientUtil.reloadProxyConfig(hostname, port, "", "");
        System.out.println(HttpClientUtil.executeGet(url));
        
        index++;
        
        if(index == 500){
            flag = false;
        }else{
            Thread.sleep(1000);
        }
        }catch(Exception e){
            e.printStackTrace();
            
        }
        }
        }

}
